#ifndef SIMRENDERER_H
#define SIMRENDERER_H

// Qt
#include <QtQuick/QQuickFramebufferObject>
#include <QtGui/QOpenGLFramebufferObject>
#include <QtGui/qvector3d.h>
#include <QtGui/qmatrix4x4.h>
#include <QtGui/qopenglshaderprogram.h>
#include <QVector>

// Bullet
#include "SimPhysics.h"

/*
 *  The renderer for the sim, renders to an FBO placed within
 *  the main UI scene graph. Its meant to have only rendering code. No physics.
 *  Thats implemented in a separate class.
 *
 */
class SimRenderer : public QQuickFramebufferObject::Renderer
{
public:
    SimRenderer();
    //virtual ~SimRenderer();

protected:

    /*
     * Inline function to get a FBO at the first frame & for any resizes
     * This function is called when a new FBO is needed. This happens on the initial frame.
     * If QQuickFramebufferObject::textureFollowsItemSize is set to true,
     * it is called again every time the dimensions of the item changes.
     * The returned FBO can have any attachment. If the QOpenGLFramebufferObjectFormat
     * indicates that the FBO should be multisampled, the internal implementation of
     * the Renderer will allocate a second FBO and blit the multisampled FBO into the FBO
     * used to display the texture.
     */
    QOpenGLFramebufferObject *createFramebufferObject(const QSize &size) {
        qDebug() << "FBO needed ! SimRenderer::createFramebufferObject called";

        mProjMatrix.setToIdentity();
        mProjMatrix.perspective(60.0, (float) size.width() / (float) size.height(), 0.001, 1000);
        glViewport(0, 0, size.width(), size.height());

        QOpenGLFramebufferObjectFormat format;
        format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
        format.setSamples(4);
        return new QOpenGLFramebufferObject(size, format);
    }

    // Render a frame
    virtual void render();

    // Sync with QML item
    void synchronize(QQuickFramebufferObject * item);

protected:
    /*
     *  Rendering functions - override as needed
     *  The order may vary to get a specific result on screen
     *  All rendering functions should follow the naming convention 'render...()'
     */

    // The grid should subdivide
    virtual void renderPerspectiveGrid();

    // Will be needed later
    virtual void renderOrthoGrid(){}

    // Line drawing for debugging
    virtual void renderPhysicsDebugDraw();

    // Actual meshes - will be expanded later to render with more visual attributes
    virtual void renderPhysicsMeshes();

    // The text and other helpful info in ortho mode
    virtual void renderHUD();

private:

    // Geometry creation
    void createGrid();
    void createGeometry();

    double mAlpha;
    double mBeta;
    double mDistance;

    QMatrix4x4 mProjMatrix;

    QVector<QVector3D> mVertices;
    QVector<QVector3D> mNormals;
    QVector<QVector3D> mColors;

    // Grid drawing
    QVector<QVector3D> mGridVertices;
    QVector<QVector3D> mGridColors;

    QOpenGLShaderProgram mProgram;
    int mVertexAttrLoc;
    int mNormalAttrLoc;
    int mColorAttrLoc;
    int mMatrixUniformLoc;

    // Physics
    SimPhysics mPhysics;
};

#endif // SIMRENDERER_H
